package ar.uade.edu.fain.ad.server.service;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.List;

import ar.uade.edu.fain.ad.common.exception.OrdenCompraInexistenteException;
import ar.uade.edu.fain.ad.common.exception.ProductoInexistenteException;
import ar.uade.edu.fain.ad.common.remote.SwingProcessRemoto;
import ar.uade.edu.fain.ad.common.transfer.ImportacionRemitoVO;
import ar.uade.edu.fain.ad.common.transfer.ItemRemitoVO;
import ar.uade.edu.fain.ad.common.transfer.NotaDevolucionVO;
import ar.uade.edu.fain.ad.common.transfer.OrdenCompraVO;
import ar.uade.edu.fain.ad.common.transfer.ProductoVO;
import ar.uade.edu.fain.ad.common.transfer.RemitoVO;
import ar.uade.edu.fain.ad.server.business.DepositoCentral;
import ar.uade.edu.fain.ad.server.business.ItemOrdenCompra;
import ar.uade.edu.fain.ad.server.business.ItemRemito;
import ar.uade.edu.fain.ad.server.business.NotaDevolucion;
import ar.uade.edu.fain.ad.server.business.OrdenCompra;
import ar.uade.edu.fain.ad.server.business.Producto;
import ar.uade.edu.fain.ad.server.business.Remito;
import ar.uade.edu.fain.ad.server.dao.DepositoCentralDAO;
import ar.uade.edu.fain.ad.server.dao.NotaDevolucionDAO;
import ar.uade.edu.fain.ad.server.dao.OrdenCompraDAO;
import ar.uade.edu.fain.ad.server.dao.ProductoDAO;
import ar.uade.edu.fain.ad.server.dao.jpa.ProductoJpaDAO;
import ar.uade.edu.fain.ad.server.util.DateUtils;
import ar.uade.edu.fain.ad.server.util.persistence.TransactionManager;

public class GeneralRemoto extends UnicastRemoteObject implements
		SwingProcessRemoto {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private TransactionManager transactionManager;

	private ProductoDAO productoDAO;

	private OrdenCompraDAO ordenCompraDAO;

	private DepositoCentralDAO depositoCentralDAO;

	private NotaDevolucionDAO notaDevolucionDAO;

	public GeneralRemoto() throws RemoteException {
		super();
	}

	public TransactionManager getTransactionManager() {
		return transactionManager;
	}

	public void setTransactionManager(TransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}

	public ProductoDAO getProductoDAO() {
		return productoDAO;
	}

	public void setProductoDAO(ProductoDAO productoDAO) {
		this.productoDAO = productoDAO;
	}

	public OrdenCompraDAO getOrdenCompraDAO() {
		return ordenCompraDAO;
	}

	public void setOrdenCompraDAO(OrdenCompraDAO ordenCompraDAO) {
		this.ordenCompraDAO = ordenCompraDAO;
	}

	public DepositoCentralDAO getDepositoCentralDAO() {
		return depositoCentralDAO;
	}

	public void setDepositoCentralDAO(DepositoCentralDAO depositoCentralDAO) {
		this.depositoCentralDAO = depositoCentralDAO;
	}

	public NotaDevolucionDAO getNotaDevolucionDAO() {
		return notaDevolucionDAO;
	}

	public void setNotaDevolucionDAO(NotaDevolucionDAO notaDevolucionDAO) {
		this.notaDevolucionDAO = notaDevolucionDAO;
	}

	@Override
	public List<NotaDevolucionVO> buscarDevoluciones() throws RemoteException {

		List<NotaDevolucionVO> listaVO = NotaDevolucionDAO.Util
				.buscarDevoluciones();

		return listaVO;
	}

	@Override
	public void registrarMercaderia(List<ProductoVO> mercaderias)
			throws RemoteException {

		ProductoJpaDAO.registrarMercaderia(mercaderias);

	}

	@Override
	public List<ProductoVO> controlarMercaderiaDeposito()
			throws RemoteException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ImportacionRemitoVO procesarRemito(final RemitoVO remitoVO)
			throws ProductoInexistenteException, RemoteException,
			OrdenCompraInexistenteException {
		final Remito remito = construirDesde(remitoVO);
		final DepositoCentral depositoCentral = buscarDepositoCentral();
		depositoCentral.recibir(remito);
		persistirResultadoDe(remito);
		getDepositoCentralDAO().update(depositoCentral);
		final ImportacionRemitoVO importacionRemitoVO = 
				crearImportacionVO(remito);
		getTransactionManager().commit();
		return importacionRemitoVO;
	}

	private void persistirResultadoDe(final Remito remito) {
		for (ItemRemito itemRemito : remito.getItems()) {
			getOrdenCompraDAO().actualizarItem(itemRemito.getItemOrdenCompra());
		}
		for (NotaDevolucion notaDevolucion : remito.getNotasDevolucion()) {
			getNotaDevolucionDAO().save(notaDevolucion);
		}
	}

	private ImportacionRemitoVO crearImportacionVO(final Remito remito) {
		final ImportacionRemitoVO importacionRemitoVO = new ImportacionRemitoVO();
		importacionRemitoVO.setRemitoVO(remito.toVO());
		for (NotaDevolucion devolucion : remito.getNotasDevolucion()) {
			importacionRemitoVO.getNotaDevolucionVOs().add(devolucion.toVO());
		}
		for (ItemOrdenCompra itemOrdenCompra : remito.getFaltantes()) {
			importacionRemitoVO.getFaltantesItemOrdenCompraVOs().add(
					itemOrdenCompra.toVO());
		}
		return importacionRemitoVO;
	}

	private DepositoCentral buscarDepositoCentral() {
		return getDepositoCentralDAO().getAll().iterator().next();
	}

	private Remito construirDesde(RemitoVO remitoVO)
			throws OrdenCompraInexistenteException,
			ProductoInexistenteException {
		final Remito remito = new Remito();
		remito.setId(remitoVO.getId());
		for (ItemRemitoVO itemRemitoVO : remitoVO.getItems()) {
			final ItemRemito itemRemito = new ItemRemito();
			itemRemito.setCantidad(itemRemitoVO.getCantidad());
			itemRemito.setFechaCaducidad(
					DateUtils.limpiarHora(itemRemitoVO.getFechaCaducidad()));
			final Long productoId = itemRemitoVO.getProducto().getId();
			final Producto producto = getProductoDAO().get(productoId);
			if (producto == null) {
				final ProductoVO productoVO = new ProductoVO();
				productoVO.setId(productoId);
				throw new ProductoInexistenteException(productoVO);
			}
			itemRemito.setProducto(producto);
			final Long ordenCompraId = itemRemitoVO.getOrdenCompra().getId();
			final OrdenCompra ordenCompra = getOrdenCompraDAO().get(
					ordenCompraId);
			if (ordenCompra == null) {
				final OrdenCompraVO ordenCompraVO = new OrdenCompraVO();
				ordenCompraVO.setId(ordenCompraId);
				throw new OrdenCompraInexistenteException(ordenCompraVO);
			}
			itemRemito.setOrdenCompra(ordenCompra);
			remito.getItems().add(itemRemito);
		}
		return remito;
	}

}
